package com.hksj.aqm.service;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.hksj.aqm.dto.AqmLargeScreenDTO;
import com.hksj.aqm.dto.ExportAqmDeviceHistoryDTO;
import com.hksj.aqm.mapper.AqmLargeScreenMapper;
import com.hksj.aqm.vo.AqmAlarmStatusVO;
import com.hksj.aqm.vo.AqmAlarmTypeVO;
import com.hksj.aqm.vo.AqmDeviceHistoryVO;
import com.hksj.base.service.DefaultDeviceService;
import com.hksj.cbm.service.DeviceInstanceService;
import com.hksj.cbm.util.CellStyleStrategy;
import com.hksj.cbm.vo.SpaceModelVO;
import com.hksj.common.core.common.PropertyCodeUnitEnum;
import com.hksj.common.core.common.SpecialityModelCodeEnum;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class AqmLargeScreenService {

    private static final Logger log = org.slf4j.LoggerFactory.getLogger(AqmLargeScreenService.class);


    @Resource
    private AqmLargeScreenMapper aqmLargeScreenMapper;

    @Autowired
    private DeviceInstanceService deviceInstanceService;

    @Autowired
    private DefaultDeviceService defaultDeviceService;


    /**
     * 根据类型查询AQI报警信息
     * 此方法主要用于大气监测系统的大屏幕上显示不同类型的报警比例
     * 它首先从数据库中查询出各种类型的报警数量，然后计算每种类型报警数量占总报警数量的比例
     *
     * @param dto 包含查询条件的对象，用于数据库查询
     * @return 返回一个列表，包含每种类型报警的数量及其占总报警数量的比例
     */
    public List<AqmAlarmTypeVO> queryAqmAlarmByType(AqmLargeScreenDTO dto) {
        dto.setCode(SpecialityModelCodeEnum.air_quality.getCode());
        // 初始化数据
        List<String> propertyList = PropertyCodeUnitEnum.getAllCode();
        List<AqmAlarmTypeVO> resultList = propertyList.stream().map(property -> {
            AqmAlarmTypeVO alarmTypeVO = new AqmAlarmTypeVO();
            alarmTypeVO.setProperty(property);
            alarmTypeVO.setPropertyName(PropertyCodeUnitEnum.getName(property));
            return alarmTypeVO;
        }).collect(Collectors.toList());
        // 从数据库查询AQI报警类型数据
        List<AqmAlarmTypeVO> list = aqmLargeScreenMapper.queryAqmAlarmByType(dto);

        // 如果查询结果为空，直接返回一个空列表
        if (CollectionUtils.isEmpty(list)){
            return resultList;
        }

        // 计算所有类型报警数量的总和
        int totalNum = list.stream().mapToInt(AqmAlarmTypeVO::getAlarmNum).sum();

        // 如果总报警数大于0，计算每种类型报警的数量占总报警数量的比例
        if (totalNum > 0){
            list.forEach(item -> {
                // 计算并设置每种类型报警的比例
                item.setAlarmProportion(item.getAlarmNum() * 1.0 / totalNum);
            });
        }
        Map<String, AqmAlarmTypeVO> map = list.stream().collect(Collectors.toMap(AqmAlarmTypeVO::getProperty, item -> item));
        resultList.forEach(item -> {
            if (map.containsKey(item.getProperty())){
                item.setAlarmNum(map.get(item.getProperty()).getAlarmNum());
                item.setAlarmProportion(map.get(item.getProperty()).getAlarmProportion());
            }
        });

        // 返回处理后的列表
        return resultList;
    }

    /**
     * 查询气体报警状态
     *
     * @param dto 查询条件对象
     * @return 报警状态列表
     */
    public List<AqmAlarmStatusVO> queryAqmAlarmStatus(AqmLargeScreenDTO dto) {
        if (ObjectUtils.isEmpty(dto.getCode())){
            dto.setCode(SpecialityModelCodeEnum.air_quality.getCode());
        }
        List<AqmAlarmStatusVO> list = aqmLargeScreenMapper.queryAqmAlarmStatus(dto);
        // 如果查询结果为空，直接返回空列表
        if (CollectionUtils.isEmpty(list)) {
            return new ArrayList<>();
        }
        //拼接单位
        list.forEach(item -> {
            String unit = PropertyCodeUnitEnum.getVal(item.getProperty());
            item.setValue(item.getValue() + unit);
        });
        // 提取所有查询结果中的路径信息
        List<String> pathList = list.stream()
                .map(AqmAlarmStatusVO::getPaths)
                .filter(Objects::nonNull) // 过滤掉空的路径信息
                .collect(Collectors.toList());
        // 如果路径信息为空，直接返回原查询结果
        if (CollectionUtils.isEmpty(pathList)) {
            return list;
        }
        // 将路径信息转换为UTF-8编码，并映射到相应的气体报警对象上
        Map<String, List<SpaceModelVO>> pathNameMap = deviceInstanceService.devicePathConvertToUTF8(pathList);
        // 如果转换结果不为空，更新气体报警对象中的路径信息
        if (!ObjectUtils.isEmpty(pathNameMap)) {
            list.forEach(alarmVO -> {
                List<SpaceModelVO> spaceModelVOList = pathNameMap.get(alarmVO.getPaths());
                if (StringUtils.isNotBlank(dto.getPaths()) && CollUtil.isNotEmpty(spaceModelVOList)){
                    spaceModelVOList = spaceModelVOList.stream().filter(spaceModelVO -> !dto.getPaths().contains(spaceModelVO.getId().toString())).collect(Collectors.toList());
                }
                alarmVO.setSpaceModelVOList(spaceModelVOList);
            });
        }

        return list;
    }

    public void exportAqmDeviceHistory(ExportAqmDeviceHistoryDTO dto, HttpServletResponse response) throws IOException {
        //查询历史数据
        String paths = aqmLargeScreenMapper.queryAqmDevicePaths(dto);

        String tableName = defaultDeviceService.getTableName(dto.getProductId());
        List<AqmDeviceHistoryVO> list = new ArrayList<>();
        try {
            list = aqmLargeScreenMapper.queryAqmDeviceHistory(dto,tableName);
        }catch (Exception e){
            log.error("Error querying table {}: {}", tableName, e.getMessage(), e);
        }

        // 设置序号
        if (!CollectionUtils.isEmpty(list)){
            int i=1;
            for (AqmDeviceHistoryVO item : list){
                item.setSeq(i++);
            }
        }

        String fileName = new StringBuffer()
                .append("空气质量设备历史记录")
                .append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
                        .format(new Date()))
                .append(".xlsx")
                .toString();

        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8"));

        EasyExcel.write(response.getOutputStream(), AqmDeviceHistoryVO.class)
                .registerWriteHandler(new CellStyleStrategy(Collections.singletonList(0),new WriteCellStyle(), new WriteCellStyle()))
                .sheet(paths)
                .doWrite(list);
    }

    public List<AqmAlarmTypeVO> queryAqmAlarmDeviceByType4HJGL(AqmLargeScreenDTO dto) {
        dto.setCode(SpecialityModelCodeEnum.environment_management.getCode());
        // 初始化数据
        List<String> propertyList = PropertyCodeUnitEnum.getAllCode();
        List<AqmAlarmTypeVO> resultList = propertyList.stream().map(property -> {
            AqmAlarmTypeVO alarmTypeVO = new AqmAlarmTypeVO();
            alarmTypeVO.setProperty(property);
            alarmTypeVO.setPropertyName(PropertyCodeUnitEnum.getName(property));
            return alarmTypeVO;
        }).collect(Collectors.toList());

        AqmAlarmTypeVO pressureType = new AqmAlarmTypeVO();
        pressureType.setProperty("pressure");
        pressureType.setPropertyName("压力");
        resultList.add(pressureType);

        // 从数据库查询AQI报警类型数据
        List<AqmAlarmTypeVO> list = aqmLargeScreenMapper.queryAqmAlarmByType(dto);

        // 如果查询结果为空，直接返回一个空列表
        if (CollectionUtils.isEmpty(list)){
            return resultList;
        }

        // 计算所有类型报警数量的总和
        int totalNum = list.stream().mapToInt(AqmAlarmTypeVO::getAlarmNum).sum();

        // 如果总报警数大于0，计算每种类型报警的数量占总报警数量的比例
        if (totalNum > 0){
            list.forEach(item -> {
                // 计算并设置每种类型报警的比例
                item.setAlarmProportion(item.getAlarmNum() * 1.0 / totalNum);
            });
        }
        Map<String, AqmAlarmTypeVO> map = list.stream().collect(Collectors.toMap(AqmAlarmTypeVO::getProperty, item -> item));
        resultList.forEach(item -> {
            if (map.containsKey(item.getProperty())){
                item.setAlarmNum(map.get(item.getProperty()).getAlarmNum());
                item.setAlarmProportion(map.get(item.getProperty()).getAlarmProportion());
            }
        });

        // 返回处理后的列表
        return resultList;
    }
}
